using System;
using System.IO;
using System.Reflection;
using AvantGameMachine.DataManagement;

namespace AvantGameMachine
{
	namespace FileSystem
	{
		internal delegate bool LoadFile(FileInformation _info);

		public class FileSystemManager
		{
			private const string FileManagerBaseAddress = "FileSystem";
			private StructuredData fileSystemDataPointer = null;
            private ulong totalRead = 0;
            private long bRead = 0;
            private bool loadingData = false;

			internal FileSystemManager()
			{
				fileSystemDataPointer = new StructuredData();
				fileSystemDataPointer.Name = FileManagerBaseAddress;
                AGMPlatform.SData.AddNode(fileSystemDataPointer,new Address("/"),0);
			}

            internal void Init()
            {
                LoadAllDirectories();
            }

			internal void LoadDirectory(StructuredData _data,Address _dir) {
				DirectoryInfo dirInfo = new DirectoryInfo(_dir.ToString());

		        // Get the files in the directory and print out some information about them.
		        FileInfo[] fileNames = dirInfo.GetFiles("*.*");


		        foreach (FileInfo fi in fileNames)
		        {
					StructuredData newNode = new StructuredData(fi.Name);
					newNode.Data = new FileInformation(fi);
					_data.AddNode(newNode);
				}

		        DirectoryInfo[] dirInfos = dirInfo.GetDirectories("*.*");

		        foreach (DirectoryInfo d in dirInfos)
		        {
					StructuredData newData = new StructuredData(d.Name);
					newData.Data = new DirectoryInformation(d);
					_data.AddNode(newData);
					LoadDirectory(newData,new Address(_dir.ToString()+"/"+d.Name));
		        }
			}

			internal void LoadAllDirectories() {
				LoadDirectory(fileSystemDataPointer,new Address("."));
			}
/*			
			private bool LoadAndExecuteModule(Address _address,string _modName) {
				try {
					string name = _address.ToString();
					Assembly a = Assembly.LoadFrom(name);
					ClientWrapper hc = (ClientWrapper)a.CreateInstance(_modName+".GameMainClass"); 
					LoadClientData(_modName);
					ClientManager.GetInstance().AddClient(_modName,hc,a);
				} catch (Exception e) {
					Log.Debug(e.ToString());
					return false;
				}
				return true;
			}
            
			internal bool ExecuteModule(string _modName) {
				Address addr = new Address(_modName+"/"+_modName+".dll");
				return LoadAndExecuteModule(addr,_modName);
			}
			*/
			internal FileEntry GetFile(Address _address) {
                Address address = ConvertToFileAddress(_address);
				StructuredData data = fileSystemDataPointer.GetNodeFromAddress(address,0);
				if (data != null)
                    return (FileEntry)data.Data;
				
				return null;
			}

            internal static Address ConvertToFileAddress(Address _address)
            {
                return new Address(FileManagerBaseAddress + "/" + _address.ToString());
            }

            internal ulong GetDirectorySize(Address _address)
            {
                StructuredData shead = fileSystemDataPointer.GetNodeFromAddress(ConvertToFileAddress(_address),0);
                FileEntry head = GetFile(_address);
                if (head != null)
                {
                    if (head.IsDirectory)
                    {
                        ulong temp = 0;
                        foreach (StructuredData f in shead.Children)
                        {
                            Address newAddress = new Address(_address.ToString() + "/"+ f.Name);
                            temp += GetDirectorySize(newAddress);
                        }
                        return temp;
                    }
                    else
                    {
                        return (ulong)((FileInformation)head).Info.Length;
                    }
                }

                return 0;
            }

            public ulong TotalRead
            {
                get
                {
                    return totalRead + (ulong)bRead;
                }
            }

            internal bool DoLoadDataFromDirectory(Address _address)
            {
                bRead = 0;
                totalRead = 0;
                loadingData = true;
                bool result = LoadDataFromDirectory(_address,true);
                loadingData = false;
                return result;
            }

            internal bool LoadingData
            {
                get { return loadingData; }
            }

			private bool LoadDataFromDirectory(Address _address,bool _mthread)
            {
                try
                {
                    StructuredData data = fileSystemDataPointer.GetNodeFromAddress(ConvertToFileAddress(_address), 0);

                    foreach (StructuredData fl in data.Children)
                    {
                        if (fl.Data.GetType() == typeof(FileInformation))
                        {
                            // Load the file.
                            FileInformation fi = (FileInformation)fl.Data;
                            if (!fi.LoadFile(out bRead, _mthread))
                            {
                                return false;
                            }
                            lock (this)
                            {
                                totalRead += (ulong)bRead;
                                bRead = 0;
                            }
                        }

                        if (fl.Data.GetType() == typeof(DirectoryInformation))
                        {
                            if (!LoadDataFromDirectory(new Address(_address.ToString() + "/" + fl.Name), _mthread))
                            {
                                return false;
                            }
                        }
                    }

                    return true;
                }
                catch (Exception e)
                {
                    AGMPlatform.log.Debug(e.ToString());
                    return false;
                }
			}
		}
	}
}
